//
//  XYAtttributeLabel.m
//  PeiJue
//
//  Created by lxy on 2018/3/1.
//  Copyright © 2018年 lixiya. All rights reserved.
//

#import "XYAtttributeLabel.h"

@interface XYAtttributeLabel ()

/** 文本内容存储 */
@property(nonatomic, strong) NSTextStorage *textStorage;
/** 文本布局管理 */
@property(nonatomic, strong) NSLayoutManager *layoutManager;
/** 文本绘制的范围 */
@property(nonatomic, strong) NSTextContainer *textContainer;
/** 富文本链接类型 */
@property(nonatomic, assign) XYAtttributeLabelLinkType linkType;

/** 保存所有富文本字段位置的数组 */
@property(nonatomic, strong) NSMutableArray *linkRanges;
/** 保存自定义链接字段位置的数组 */
@property(nonatomic, strong) NSMutableArray *customlinkRanges;
/** atRange 保存 @ 富文本的字段位置的数组 */
@property(nonatomic, strong) NSMutableArray *atRanges;
/** jingRange 保存 # 富文本的字段位置的数组 */
@property(nonatomic, strong) NSMutableArray *jingRanges;
/** urlRange 保存 url 富文本的字段位置的数组 */
@property(nonatomic, strong) NSMutableArray *urlRanges;

/** 选中链接文字位置 */
@property(nonatomic, assign) NSRange selectedRange;


@end

@implementation XYAtttributeLabel

#pragma mark - Overrides
- (instancetype)init {
    self = [super init];
    if (self) {
        [self prepareCongfigInfomation];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self prepareCongfigInfomation];
    }
    return self;
}

/** 绘制textStorage的文本内容--不能调用super */
- (void)drawTextInRect:(CGRect)rect {
    // 这里顺序是先背景 在文字
    // 在 selectedRange 位置绘制背景
    if (self.selectedRange.length > 0) {
        [self.layoutManager drawBackgroundForGlyphRange:self.selectedRange atPoint:CGPointZero];
    }
    
    // 绘制范围
    NSRange range = NSMakeRange(0, self.textStorage.length);
    //Glyphs--字形---CGPoint()从原点绘制,也就是右上角
    [self.layoutManager drawGlyphsForGlyphRange:range atPoint:CGPointZero];
    
}

- (void)layoutSubviews {
    [super layoutSubviews];
    // 设置容器的大小为Label的尺寸
    self.textContainer.size = self.bounds.size;
}

#pragma mark - Privates
/** 配置信息 */
- (void)prepareCongfigInfomation {
    self.userInteractionEnabled = YES;
    
    // 1.NSTextStorage接收文本内容
    if (self.attributedText) {
        [self.textStorage setAttributedString:self.attributedText];
    }else if (self.text) {
        [self.textStorage setAttributedString:[[NSAttributedString alloc] initWithString:self.text]];
    }else{
        [self.textStorage setAttributedString:[[NSAttributedString alloc] initWithString:@""]];
    }
    
    // 2.设置对象关系
    [self.layoutManager addTextContainer:self.textContainer];
    [self.textStorage addLayoutManager:self.layoutManager];
}

/** 文本发生改变的时候，更新文本内容存储，更新布局重新显示 */
- (void)updateTextStorage {
    
    // 初始化数据
    self.selectedRange = NSMakeRange(0, 0);

    [self.customlinkRanges removeAllObjects];
    self.customlinkRanges = nil;
    
    [self.linkRanges removeAllObjects];
    self.linkRanges = nil;
    
    [self.atRanges removeAllObjects];
    self.atRanges = nil;
    
    [self.jingRanges removeAllObjects];
    self.jingRanges = nil;
    
    [self.urlRanges removeAllObjects];
    self.urlRanges = nil;
    
    if (!self.attributedText) return;

    // 1.设置段略样式
    NSMutableAttributedString *attrStringM = [self addParagraphStyle:self.attributedText];
    
    // 2.正则匹配
    [self addRegularMatch:attrStringM];
    
    // 3.设置文本链接颜色及其他属性
    [self addTextLinkAttribute:attrStringM];
    
    // 4.添加到 NSTextStorage
    [self.textStorage setAttributedString:attrStringM];
    
    // 5.重新绘制 异步执行的,setNeedsDisplay会自动调用drawRect方法
    [self setNeedsDisplay];
}

/** 设置段略样式 */
- (NSMutableAttributedString *)addParagraphStyle:(NSAttributedString *)attrString {
    NSMutableAttributedString *attrStringM = [[NSMutableAttributedString alloc] initWithAttributedString:attrString];
    if (attrStringM.length == 0) {
        return attrStringM;
    }
    
    //从(0,0)点开始,也就是从text的第一个字符开始
    NSRange zeroRange = NSMakeRange(0, 0);
    NSRange range = NSMakeRange(0, attrStringM.length);
    
    NSMutableDictionary *attrDic = [NSMutableDictionary dictionaryWithDictionary:[attrStringM attributesAtIndex:0 effectiveRange:&zeroRange]];
    
    //ByWordWrapping 按照单词分割换行，保证换行时的单词完整。
    //ByCharWrapping 按照字母换行，可能会在换行时将某个单词拆分到两行
    NSMutableParagraphStyle *paragraphStyle = attrDic[NSParagraphStyleAttributeName];
    if (paragraphStyle) {
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
    }else{
        paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        // NSLineBreakByCharWrapping
        // NSLineBreakByWordWrapping
        paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
        
        [attrDic setValue:paragraphStyle forKey:NSParagraphStyleAttributeName];
        [attrStringM addAttributes:attrDic range:range];
    }
    
    
    return attrStringM;
}

/** 正则匹配 匹配所有链接颜色:URL,#话题#,@好友  放到数组 linkRanges 里*/
- (void)addRegularMatch:(NSMutableAttributedString *)attrStringM {
    NSArray *patterns = @[@"[a-zA-Z]*://[a-zA-Z0-9/\\.]*", @"#.*?#", @"@[\\u4e00-\\u9fa5a-zA-Z0-9_-]*"];
    
    //存储所有的匹配结果前,将原来的清空
    [self.linkRanges removeAllObjects];
    
    NSRange regexRange = NSMakeRange(0, attrStringM.length);
    for (NSString *pattern in patterns) {
        // 1.正则匹配,这里不能保证一定能匹配到
        NSError *error;
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&error];
        if (regex) {
            // 2.获取匹配结果
            NSArray *matchs = [regex matchesInString:attrStringM.string options:NSMatchingReportProgress range:regexRange];
            
            // 3.遍历所有匹配结果,添加到数组中
            //当解析出的数组至少有一个对象时，即原文本中存在至少一个符合规则的字段
            if (matchs.count>0) {
                for (NSTextCheckingResult *result in matchs) {
                    NSLog(@"匹配节点---%@",result);
                    //从NSTextCheckingResult类中取出range属性 [result rangeAtIndex:0]
                    [self.linkRanges addObject:[NSValue valueWithRange:result.range]];
                }
            }
        }
    }
    
    NSLog(@"匹配结果self.linkRanges---%@",self.linkRanges);
}

/** 设置文本链接颜色及其他属性 */
- (void)addTextLinkAttribute:(NSMutableAttributedString *)attrStringM {
    if (attrStringM.length == 0) {
        return;
    }
    
    //从(0,0)点开始,也就是从text的第一个字符开始
    NSRange zeroRange = NSMakeRange(0, 0);
    NSRange range = NSMakeRange(0, attrStringM.length);
    
    NSMutableDictionary *attrDic = [NSMutableDictionary dictionaryWithDictionary:[attrStringM attributesAtIndex:0 effectiveRange:&zeroRange]];
    // 设置全局颜色字体
    [attrDic setValue:self.font forKey:NSFontAttributeName];
    [attrDic setValue:self.customTextColor forKey:NSForegroundColorAttributeName];
    [attrStringM addAttributes:attrDic range:range];
    
    // 设置富文本颜色字体
    [self.linkRanges enumerateObjectsUsingBlock:^(NSValue *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [attrDic setValue:self.linkTextColor forKey:NSForegroundColorAttributeName];
        [attrStringM setAttributes:attrDic range:[obj rangeValue]];
    }];
    
}

/** 根据正则表达式，返回匹配结果的数组 */
- (NSMutableArray *)getRegularResultRangesWithPattern:(NSString *)pattern{
    NSMutableArray *ranges = [NSMutableArray array];
    
    NSError *error;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&error];
    if (regex) {
        NSArray *matchs = [regex matchesInString:self.textStorage.string options:NSMatchingReportProgress range:NSMakeRange(0, self.textStorage.length)];
        if (matchs.count>0) {
            for (NSTextCheckingResult *result in matchs) {
                [ranges addObject:[NSValue valueWithRange:result.range]];
            }
        }
    }
    return ranges;
}

/** 根据点击位置的索引，判断富文本链接所属类型 */
- (BOOL)judgeLinkTypeAtIndex:(NSUInteger)index inRanges:(NSMutableArray *)ranges{
    
    for (NSValue *obj in ranges) {
        NSRange range = [obj rangeValue];
        if (NSLocationInRange(index, range)) {
            self.selectedRange = range;
            [self modifyAtttributesWithSelected:YES];
            NSString *strSub = [self.textStorage.string substringWithRange:range];
            NSLog(@"选中文字----  %@  ----",strSub);
            return YES;
        }
    }
    
    return NO;
}

/** 选中 和 取消选中时 设置被选中文字的背景颜色 */
- (void)modifyAtttributesWithSelected:(BOOL)isSelected {
    if (self.selectedRange.length == 0) {
        return;
    }
    
    NSMutableDictionary *attrDic = [NSMutableDictionary dictionaryWithDictionary:[self.textStorage attributesAtIndex:0 effectiveRange:nil]];
    [attrDic setValue:self.linkTextColor forKey:NSForegroundColorAttributeName];
    if (isSelected) {
        [attrDic setValue:self.linkSelectedBgColor forKey:NSBackgroundColorAttributeName];
    }else{
        [attrDic setValue:[UIColor clearColor] forKey:NSBackgroundColorAttributeName];
    }
    [self.textStorage addAttributes:attrDic range:self.selectedRange];
    
    [self setNeedsDisplay];
    
}

#pragma mark - Publics
- (void)addCustomLinkWithString:(NSString *)linkText linkRange:(NSRange)linkRange {
    [self.customlinkRanges addObject:[NSValue valueWithRange:linkRange]];
    
    NSMutableDictionary *attrDic = [NSMutableDictionary dictionaryWithDictionary:[self.textStorage attributesAtIndex:0 effectiveRange:nil]];
    [attrDic setValue:self.linkTextColor forKey:NSForegroundColorAttributeName];
    [self.textStorage addAttributes:attrDic range:linkRange];
    
    [self setNeedsDisplay];
}

#pragma mark - Touch事件处理
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //获取用户点击的位置
    CGPoint point = [touches.anyObject locationInView:self];
    //获取当前点中字符的索引
    NSUInteger index = [self.layoutManager glyphIndexForPoint:point inTextContainer:self.textContainer];
  
    // 判断富文本类型
    if ([self judgeLinkTypeAtIndex:index inRanges:self.atRanges]) {
        self.linkType = XYAtttributeLabelLinkTypeAt;
    }else if ([self judgeLinkTypeAtIndex:index inRanges:self.jingRanges]){
        self.linkType = XYAtttributeLabelLinkTypeJing;
    }else if ([self judgeLinkTypeAtIndex:index inRanges:self.urlRanges]){
        self.linkType = XYAtttributeLabelLinkTypeUrl;
    }else if ([self judgeLinkTypeAtIndex:index inRanges:self.customlinkRanges]){
        self.linkType = XYAtttributeLabelLinkTypeCustom;
    }else{
        self.linkType = XYAtttributeLabelLinkTypeNone;
    }
    
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (self.selectedRange.length == 0) {
        return;
    }
    
    //获取用户点击的位置
    CGPoint point = [touches.anyObject locationInView:self];
    //获取当前点中字符的索引
    NSUInteger index = [self.layoutManager glyphIndexForPoint:point inTextContainer:self.textContainer];
    //判断触摸移动是否在选中范围内
    if (!NSLocationInRange(index, self.selectedRange)) {
        [self modifyAtttributesWithSelected:NO];
    }
    
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (self.selectedRange.length == 0) {
        return;
    }
    
    [self modifyAtttributesWithSelected:NO];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (self.selectedRange.length == 0) {
        return;
    }
    
    NSString *strSub = [self.textStorage.string substringWithRange:self.selectedRange];
    if (self.delegate && [self.delegate respondsToSelector:@selector(atttributeLabel:didSelectedLinkText:linkRange:linkType:)]) {
        [self.delegate atttributeLabel:self didSelectedLinkText:strSub linkRange:self.selectedRange linkType:self.linkType];
    }
    
    [self modifyAtttributesWithSelected:NO];
    // 重置 self.selectedRange
    self.selectedRange = NSMakeRange(0, 0);
}


#pragma mark - Getters && Setters
/** 文本发生改变的时候，更新文本内容存储，更新布局重新显示 */
- (void)setText:(NSString *)text {
    if (!text) return;
    [super setText:text];
    
    [self updateTextStorage];
}

/** 文本发生改变的时候，更新文本内容存储，更新布局重新显示 */
- (void)setAttributedText:(NSAttributedString *)attributedText {
    if (!attributedText) return;
    [super setAttributedText:attributedText];
    
    [self updateTextStorage];
}

- (NSTextStorage *)textStorage {
    if (!_textStorage) {
        _textStorage = [[NSTextStorage alloc] init];
    }
    return _textStorage;
}

- (NSLayoutManager *)layoutManager {
    if (!_layoutManager) {
        _layoutManager = [[NSLayoutManager alloc] init];
    }
    return _layoutManager;
}


- (NSTextContainer *)textContainer {
    if (!_textContainer) {
        _textContainer = [[NSTextContainer alloc] init];
    }
    return _textContainer;
}

- (UIColor *)customTextColor {
    return _customTextColor ?: [UIColor blackColor];
}

- (UIColor *)linkTextColor {
    return _linkTextColor ?: [UIColor blueColor];
    
}

- (UIColor *)linkSelectedBgColor {
    return _linkSelectedBgColor ?: [UIColor darkGrayColor];
}

- (NSMutableArray *)linkRanges {
    if (!_linkRanges) {
        _linkRanges = [NSMutableArray array];
    }
    return _linkRanges;
}

- (NSMutableArray *)customlinkRanges {
    if (!_customlinkRanges) {
        _customlinkRanges = [NSMutableArray array];
    }
    return _customlinkRanges;
}

- (NSMutableArray *)atRanges {
    if (!_atRanges) {
        _atRanges = [self getRegularResultRangesWithPattern:@"@[\\u4e00-\\u9fa5a-zA-Z0-9_-]*"];
    }
    return _atRanges;
}

- (NSMutableArray *)jingRanges {
    if (!_jingRanges) {
        _jingRanges = [self getRegularResultRangesWithPattern:@"#.*?#"];
    }
    return _jingRanges;
}

- (NSMutableArray *)urlRanges {
    if (!_urlRanges) {
        _urlRanges = [self getRegularResultRangesWithPattern:@"[a-zA-Z]*://[a-zA-Z0-9/\\.]*"];
    }
    return _urlRanges;
}

@end
